package com.factory.rental.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.factory.rental.dto.PriceDTO;
import com.factory.rental.mapper.PriceMapper;
import com.factory.rental.model.Price;
import com.factory.rental.model.Room;
import com.factory.rental.service.PriceService;
import com.factory.rental.service.RoomService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 价格策略服务实现类
 */
@Service
public class PriceServiceImpl extends ServiceImpl<PriceMapper, Price> implements PriceService {

    private final RoomService roomService;

    @Autowired
    public PriceServiceImpl(RoomService roomService) {
        this.roomService = roomService;
    }

    @Override
    @Transactional
    public Price savePrice(PriceDTO priceDTO) {
        Price price = new Price();
        convertToEntity(priceDTO, price);
        save(price);
        return price;
    }

    @Override
    public Optional<Price> getPriceById(Long id) {
        return Optional.ofNullable(getById(id));
    }

    @Override
    public List<Price> getPricesByType(Price.PriceType type) {
        return lambdaQuery()
                .eq(Price::getType, type)
                .list();
    }

    @Override
    public List<Price> getPricesByRoomType(String roomType) {
        return lambdaQuery()
                .eq(Price::getRoomType, roomType)
                .list();
    }

    @Override
    public Page<Price> getAllPrices(Pageable pageable) {
        return page(pageable);
    }

    @Override
    @Transactional
    public Price updatePrice(Long id, PriceDTO priceDTO) {
        Price price = getById(id);
        if (price == null) {
            throw new RuntimeException("未找到指定ID的价格策略");
        }
        convertToEntity(priceDTO, price);
        updateById(price);
        return price;
    }

    @Override
    @Transactional
    public void deletePrice(Long id) {
        if (!removeById(id)) {
            throw new RuntimeException("删除价格策略失败");
        }
    }

    @Override
    @Transactional
    public void updatePriceStatus(Long id, boolean enabled) {
        Price price = getById(id);
        if (price == null) {
            throw new RuntimeException("未找到指定ID的价格策略");
        }
        price.setEnabled(enabled);
        updateById(price);
    }

    @Override
    public List<Price> getEffectivePrices() {
        LocalDateTime now = LocalDateTime.now();
        return lambdaQuery()
                .eq(Price::getEnabled, true)
                .le(Price::getEffectiveTime, now)
                .or()
                .isNull(Price::getEffectiveTime)
                .and(i -> i.ge(Price::getExpireTime, now).or().isNull(Price::getExpireTime))
                .list();
    }

    @Override
    public BigDecimal calculateCost(Long roomId, int days, Price.PriceType priceType) {
        Room room = roomService.getRoomById(roomId)
                .orElseThrow(() -> new RuntimeException("未找到指定ID的房间"));

        // 查找适用的价格策略
        List<Price> prices = lambdaQuery()
                .eq(Price::getType, priceType)
                .eq(Price::getEnabled, true)
                .eq(Price::getRoomType, room.getLayout())
                .le(Price::getMinArea, room.getArea())
                .ge(Price::getMaxArea, room.getArea())
                .list();

        if (prices.isEmpty()) {
            throw new RuntimeException("未找到适用的价格策略");
        }

        // 取最新的价格策略
        Price latestPrice = prices.stream()
                .max((p1, p2) -> p1.getUpdatedTime().compareTo(p2.getUpdatedTime()))
                .orElseThrow(() -> new RuntimeException("未找到适用的价格策略"));

        // 计算费用
        return latestPrice.getPrice().multiply(new BigDecimal(days));
    }

    @Override
    public List<PriceAnalysisDTO> getCostAnalysis() {
        // 这里使用MyBatis-Plus的分组查询功能
        List<Price> prices = lambdaQuery()
                .eq(Price::getEnabled, true)
                .list();

        // 按价格类型分组并计算统计数据
        return prices.stream()
                .collect(Collectors.groupingBy(Price::getType))
                .entrySet().stream()
                .map(entry -> {
                    Price.PriceType type = entry.getKey();
                    List<Price> typePrices = entry.getValue();

                    BigDecimal minPrice = typePrices.stream()
                            .map(Price::getPrice)
                            .min(BigDecimal::compareTo)
                            .orElse(BigDecimal.ZERO);

                    BigDecimal maxPrice = typePrices.stream()
                            .map(Price::getPrice)
                            .max(BigDecimal::compareTo)
                            .orElse(BigDecimal.ZERO);

                    BigDecimal avgPrice = typePrices.stream()
                            .map(Price::getPrice)
                            .reduce(BigDecimal.ZERO, BigDecimal::add)
                            .divide(new BigDecimal(typePrices.size()), 2, BigDecimal.ROUND_HALF_UP);

                    return new PriceAnalysisDTOImpl(type, avgPrice, minPrice + "-" + maxPrice, (long) typePrices.size());
                })
                .collect(Collectors.toList());
    }

    /**
     * 将DTO转换为实体类
     * @param dto DTO对象
     * @param entity 实体类对象
     */
    private void convertToEntity(PriceDTO dto, Price entity) {
        if (dto.getId() != null) {
            entity.setId(dto.getId());
        }
        entity.setName(dto.getName());
        entity.setDescription(dto.getDescription());
        entity.setPrice(dto.getPrice());
        entity.setType(dto.getType());
        entity.setRoomType(dto.getRoomType());
        entity.setMinArea(dto.getMinArea());
        entity.setMaxArea(dto.getMaxArea());
        entity.setEffectiveTime(dto.getEffectiveTime());
        entity.setExpireTime(dto.getExpireTime());
        entity.setEnabled(dto.getEnabled() != null ? dto.getEnabled() : true);
    }

    /**
     * PriceAnalysisDTO的实现类
     */
    private static class PriceAnalysisDTOImpl implements PriceAnalysisDTO {
        private final Price.PriceType priceType;
        private final BigDecimal averagePrice;
        private final String priceRange;
        private final Long strategyCount;

        public PriceAnalysisDTOImpl(Price.PriceType priceType, BigDecimal averagePrice, String priceRange, Long strategyCount) {
            this.priceType = priceType;
            this.averagePrice = averagePrice;
            this.priceRange = priceRange;
            this.strategyCount = strategyCount;
        }

        @Override
        public Price.PriceType getPriceType() {
            return priceType;
        }

        @Override
        public BigDecimal getAveragePrice() {
            return averagePrice;
        }

        @Override
        public String getPriceRange() {
            return priceRange;
        }

        @Override
        public Long getStrategyCount() {
            return strategyCount;
        }
    }
}